<template>
  <div class="map-comp">
    <div :id="mapRef" :ref="mapRef"></div>
  </div>
</template>

<script>
export default {
  name: 'mapComp',
  props: {
    // 设置文本标注
    setLabelFn: {
      type: Function,
      default: null
    },
    /**
     * 地图中心点设置
     * @desc longitude: '经度',latitude = '纬度', zoom = '缩放'
     */
    centerOptions: {
      type: Object,
      default: () => ({
        longitude: 105.404,
        latitude: 35.915,
        zoom: 6
      })
    },
    /**
     * 标记点数据
     * {
     * lat: '纬度',
     * lng: '经度',
     * message: '信息',
     * icon: '标注图标url',
     * options: '信息窗口配置'
     * }
     */
    markers: {
      type: Array,
      default: null
    },
    // 地图事件
    eventFn: {
      type: Object,
      default: null
    }
  },
  data() {
    return {
      myMap: null,
      mapRef: `map${this.$getRandomNum()}`,
      // 地图位置实例
      geolocation: null
    };
  },
  watch: {
    markers: {
      deep: true,
      handler: function (list) {
        Array.isArray(list) && this.setMarker(list);
      }
    },
    centerOptions: {
      deep: true,
      handler: function (opt) {
        if (typeof opt === 'object') {
          this.setCenterAndZoom(opt);
        }
      }
    }
  },
  mounted() {
    /* eslint-disable */
    // 创建Map实例
    this.myMap = new BMapGL.Map(this.mapRef);
    this.init();
  },
  beforeDestroy() {
    this.eventFn && this.eventListener('remove');
  },
  methods: {
    async init() {
      /* eslint-disable */
      this.setCenterAndZoom();
      // 开启鼠标滚轮缩放
      this.myMap.enableScrollWheelZoom(true);
      // 地球模式
      this.myMap.setMapType(BMAP_EARTH_MAP);
      this.eventFn && this.eventListener('add');
      // await this.getLocation();
    },
    /**
     * 设置中心点
     * @param options {Object} 中心点参数
     * @desc longitude {Number} 经度 latitude {Number} 纬度 zoom {Number} 缩放
     */
    setCenterAndZoom(options) {
      if (!this.myMap) return;
      const hasObj = (obj) => this.$checkType(obj) === 'object';
      const config = hasObj(options) ? options : this.centerOptions;
      // 初始化地图,设置中心点坐标和地图级别
      let {
        longitude = 105.404,
        latitude = 35.915,
        zoom = 6
      } = hasObj(config) ? config : {};
      longitude = String(longitude) ? longitude : 105.404;
      latitude = String(latitude) ? latitude : 35.915;
      zoom = String(zoom) ? zoom : 6;
      this.myMap.centerAndZoom(new BMapGL.Point(longitude, latitude), zoom);
    },
    /**
     * 事件处理
     * @param type 监听(add)或移除(remove)
     */
    eventListener(type) {
      if (!this.myMap || this.$checkType(this.eventFn) !== 'object') return;
      Object.keys(this.eventFn).forEach(key => {
        if (this.$checkType(this.eventFn[key]) === 'function') {
          if (type === 'add') {
            this.myMap.addEventListener(key, this.eventFn[key]);
            return;
          }
          this.myMap.removeEventListener(key, this.eventFn[key]);
        }
      });
    },
    /**
     * 获取当前位置
     * @param longitude {Number} 经度
     * @param latitude {Number} 纬度
     */
    getLocation({ longitude, latitude } = {}) {
      if (!this.myMap) return;
      return new Promise(resolve => {
        if (longitude && latitude) {
          // 设置地理位置
          const point = new BMapGL.Point(longitude, latitude);
          const mk = new BMapGL.Marker(point);
          this.myMap.addOverlay(mk);
          // this.myMap.panTo(point);
          return;
        }
        this.geolocation = new BMapGL.Geolocation();
        this.geolocation.getCurrentPosition(function(r) {
          if (String(this.getStatus()) === String(BMAP_STATUS_SUCCESS)) {
            resolve(r.point);
          }
        })
      });
    },
    /**
     * 设置地图点标记
     * @param list {Array} 坐标点数据
     * @desc { lat: '纬度', lng: '经度', message: '信息(HTML|String)', options: '信息窗口配置' }
     */
    setMarker(list) {
      if (!Array.isArray(list) || !list.length || !this.myMap) return;
      this.clearOverlays();
      list.forEach(item => {
        const { lat, lng, message, icon, options = {}, evtFn, infoEvt } = item;
        if (isNaN(parseInt(lat)) || isNaN(parseInt(lng))) return;
        const point = new BMapGL.Point(item.lng, item.lat);
        // 创建点标记
        let markerOptions = null;
        if (icon) {
          markerOptions = {
            icon: new BMapGL.Icon(icon, new BMapGL.Size(42, 42))
          }
        }
        const marker = new BMapGL.Marker(point, markerOptions);
        this.myMap.addOverlay(marker);
        // 点标记添加点击事件
        marker.addEventListener('click', async (e) => {
          typeof evtFn === 'function' && await evtFn(e, item);
          if (!message) return;
          // 创建信息窗口
          const opts = {
            width: 200,
            height: 100,
            title: '',
            ...options
          };
          const infoWindow = new BMapGL.InfoWindow(message, opts);
          // 开启信息窗口
          this.myMap.openInfoWindow(infoWindow, point);
          // 地图窗口
          if (infoWindow && typeof infoEvt === 'function') {
            // if (!infoWindow.isOpen()) {
            //   // 如果没有打开，则监听打开事件
            //   infoWindow.addEventListener('open', () => {
            //     infoEvt(infoWindow, e);
            //   });
            //   return;
            // }
            infoEvt(infoWindow, e);
          }
        });
      });
    },
    /**
     * 清除覆盖物
     * @param Overlay 覆盖物的抽象基类  map.getOverlays()
     */
    clearOverlays(Overlay) {
      if (!this.myMap) return;
      if (Overlay) {
        // 从地图中移除某个覆盖物
        this.myMap.removeOverlay(Overlay);
        return;
      }
      // 清除地图上所有覆盖物
      this.myMap.clearOverlays();
    },
    /**
     * 设置地图文本标注
     * @param longitude {Number} 经度
     * @param latitude {Number} 纬度
     * @param content {String} 文本内容
     */
    setLabel({ longitude, latitude, content = '' } = {}) {
      if (!this.myMap || !longitude || !latitude) return;
      // 设置标注的地理位置
      const point = new BMapGL.Point(longitude, latitude);
      // 设置标注的偏移量
      const offset = new BMapGL.Size(10, 20);
      // 创建文本标注
      const label = new BMapGL.Label(content, {
        offset,
        position: point,
      });
      if (typeof this.setLabelFn === 'function') {
        this.setLabelFn(label);
      }
      this.myMap.addOverlay(label);
      return label;
    }
  }
};
</script>

<style lang="scss" scoped>
.map-comp {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  > div {
    width: 100%;
    height: 100%;
  }
}
</style>
